package com.semanticweb.webapp.ontology;

import com.semanticweb.webapp.model.ontology.Item;

public class OntHelper {

    public static final String ONT_NOTE = "note";
    public static final String ONT_DIMENSION = "dimension";
    public static final String ONT_NUMBER = "number";
    public static final String ONT_MEASUREMENT = "measurement";

    public static void toRDFNote(final String id, final String note, final String uniqueIdentifer, final CType type) {
        toRDFValueWithType(id, CIDOC.P3, CIDOC.E62, note, Ont.formatURIPart(ONT_NOTE, uniqueIdentifer), type);
    }

    public static String fromRDFNote(final String id, final CType type) {
        return fromRDFValueWithType(id, CIDOC.P3, CIDOC.E62, type);
    }

    public static void toRDFDimension(final String id, final Double number, final String unit, final CType type) {
        if (number == null && unit == null) {
            return;
        }

        Ont.typeCheck(type);

        final Query q = new Query();
        final String itemURI = Item.formatItemURI(id);
        String[] result = null;

        if (number != null && unit != null) {
            result = q.select("dim").type("dim", CIDOC.E54.queryValue()).type("number", CIDOC.E60.queryValue())
                    .label("number", number.toString()).type("unit", CIDOC.E58.queryValue()).label("unit", unit)
                    .connect("dim", CIDOC.P2.queryValue(), type.queryValue())
                    .connect("dim", CIDOC.P90.queryValue(), "number").connect("dim", CIDOC.P91.queryValue(), "unit")
                    .find();
        }

        String dimURI;
        if (result == null || result.length == 0) {
            dimURI = Ont.formatURI(id, ONT_DIMENSION, type.getValue());
            final String numberURI = Ont.formatURI(id, ONT_NUMBER, type.getValue());
            String measurementUnitURI;

            Ont.getOntology().createIndividual(CIDOC.E54.getFullValue(), dimURI);
            Ont.getOntology().connectIndividuals(dimURI, CIDOC.P2.getFullValue(), type.getURI());

            // check measurement unit
            if (unit != null) {
                final String[] measurement = q.select("measurement").type("measurement", CIDOC.E58.queryValue())
                        .label("measurement", unit).find();
                if (measurement != null && measurement.length > 0) {
                    measurementUnitURI = measurement[0];
                } else {
                    measurementUnitURI = Ont.formatURI(id, ONT_MEASUREMENT, type.getValue());
                    Ont.getOntology().createIndividual(CIDOC.E58.getFullValue(), measurementUnitURI);
                    Ont.getOntology().addLabel(measurementUnitURI, unit);
                    Ont.getOntology().connectIndividuals(dimURI, CIDOC.P91.getFullValue(), measurementUnitURI);
                }
            }

            // number
            if (number != null) {
                Ont.getOntology().createIndividual(CIDOC.E60.getFullValue(), numberURI);
                Ont.getOntology().addLabel(numberURI, number.toString());
                Ont.getOntology().connectIndividuals(dimURI, CIDOC.P90.getFullValue(), numberURI);
            }

        } else {
            dimURI = result[0];
        }

        // connect to item
        Ont.getOntology().connectIndividuals(itemURI, CIDOC.P43.getFullValue(), dimURI);
    }

    public static Double fromRDFDimensionValue(final String id, final CType type) {
        final String itemQueryValue = Item.formatItemQueryURI(id);
        final Query q = new Query();
        final String[] result = q.selectLabel().connect(itemQueryValue, CIDOC.P43.queryValue(), "dim")
                .type("dim", CIDOC.E54.queryValue()).connect("dim", CIDOC.P2.queryValue(), type.queryValue())
                .connect("dim", CIDOC.P90.queryValue(), "number").type("number", CIDOC.E60.queryValue())
                .findLabel("number");

        if (result == null || result.length == 0) {
            return null;
        }

        return Double.parseDouble(result[0]);
    }

    public static String fromRDFDimensionUnit(final String id, final CType type) {
        final String itemQueryValue = Item.formatItemQueryURI(id);
        final Query q = new Query();
        final String[] result = q.selectLabel().connect(itemQueryValue, CIDOC.P43.queryValue(), "dim")
                .type("dim", CIDOC.E54.queryValue()).connect("dim", CIDOC.P2.queryValue(), type.queryValue())
                .connect("dim", CIDOC.P91.queryValue(), "unit").type("unit", CIDOC.E58.queryValue()).findLabel("unit");

        if (result == null || result.length == 0) {
            return null;
        }

        return result[0];
    }

    /**
     * Maps value with type to Ontology.
     * 
     * @param id
     *            - item id
     * @param connector
     *            - connector class
     * @param valueClass
     *            - value class
     * @param value
     *            - value
     * @param valueSuffix
     *            - part of value's URI suffix. Value's URI will be formed as: NS + id + valueSuffix
     * @param type
     *            - type of value
     */
    public static void toRDFValueWithType(final String id, final CIDOC connector, final CIDOC valueClass,
            final String value, final String valueSuffix, final CType type) {

        if (value == null) {
            return;
        }

        Ont.typeCheck(type);

        final Query q = new Query();
        final String[] result = q.select("value").type("value", valueClass.queryValue()).label("value", value)
                .connect("value", CIDOC.P2.queryValue(), type.queryValue()).find();

        final String valueURI;
        final String itemURI = Item.formatItemURI(id);
        if (result == null || result.length == 0) {
            valueURI = Ont.formatURI(id, valueSuffix);

            Ont.getOntology().createIndividual(valueClass.getFullValue(), valueURI);
            Ont.getOntology().connectIndividuals(valueURI, CIDOC.P2.getFullValue(), type.getURI());

            Ont.getOntology().addLabel(valueURI, value);
        } else {
            valueURI = result[0];
        }

        Ont.getOntology().connectIndividuals(itemURI, connector.getFullValue(), valueURI);
    }

    /**
     * Selects value from Ontology from "value with type" mapping (
     * {@link #toRDFValueWithType(String, CIDOC, CIDOC, String, String, CType)}).
     * 
     * @param id
     * @param connector
     * @param valueClass
     * @param type
     * @return
     */
    public static String fromRDFValueWithType(final String id, final CIDOC connector, final CIDOC valueClass,
            final CType type) {
        final String itemQueryValue = Item.formatItemQueryURI(id);
        final Query q = new Query();
        final String[] result = q.selectLabel().type("id", valueClass.queryValue())
                .connect("id", CIDOC.P2.queryValue(), type.queryValue())
                .connect(itemQueryValue, connector.queryValue(), "id").findLabel("id");

        if (result == null || result.length == 0) {
            return null;
        }

        return result[0];
    }
}
